﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel.Primitives;

namespace Tests.O1.Kernel.Primitives
{
    [TestClass]
    public class EdgeTests
    {
        [TestMethod, TestCategory("Unit Test")]
        public void EdgeMaintainsCellAddressAsExpected()
        {
            var cellAddress = new CellAddress(1, 87654);
            var edge = new Edge(98, cellAddress, cellAddress, EdgeDirections.Inbound);
            edge.EndTrunkId.Equals(cellAddress.TrunkId).Should().BeTrue();
            edge.EndVertexId.Equals(cellAddress.CellId).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeWritesDataIntoPackedSizeBufferAsExpectedWithoutExceedingBounds()
        {
            var cellAddress = new CellAddress(1, 3);
            var propsAddress = new CellAddress(1, 5);

            var subject = new Edge(6, cellAddress, propsAddress, EdgeDirections.Bidirectional);
            var buffer = new byte[Edge.Size];
            Action test = () => subject.Write(buffer, 0);
            test.ShouldNotThrow();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeWritesDataValuesAsExpected()
        {
            var cellAddress = new CellAddress(1, 3);
            var propsAddress = new CellAddress(1, 5);
            var subject = new Edge(6, cellAddress, propsAddress, EdgeDirections.Bidirectional);
            
            var buffer = new byte[Edge.Size];
            subject.Write(buffer, 0);

            var actualPropsId = BitConverter.ToUInt32(buffer, 4);
            var actualEndVertexId = BitConverter.ToUInt32(buffer, 8);
            var actualEndTrunkId = BitConverter.ToUInt16(buffer, 12);
            var actualPropsTrunkId = BitConverter.ToUInt16(buffer, 14);

            actualPropsId.Should().Be(5);
            actualEndVertexId.Should().Be(3);
            actualEndTrunkId.Should().Be(1);
            actualPropsTrunkId.Should().Be(1);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeEmbedsDirectionAsExpected()
        {
            var cellAddress = new CellAddress(1, 3);
            var propsAddress = new CellAddress(1, 5);
            var subject = new Edge(6, cellAddress, propsAddress, EdgeDirections.Bidirectional);
            subject.EdgeKey.Should().Be(6);
            subject.Directions.Should().Be(EdgeDirections.Bidirectional);

            var buffer = new byte[Edge.Size];
            subject.Write(buffer, 0);

            var actualEdgeType = BitConverter.ToUInt32(buffer, 0);
            actualEdgeType.Should().Be(subject.EdgeType);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeReadsAsExpected()
        {
            var actualPropsId = BitConverter.GetBytes((uint)10);
            var actualEdgeType = BitConverter.GetBytes((uint)6);
            var actualEndVertexId = BitConverter.GetBytes((uint)3);
            var actualEndTrunkId = BitConverter.GetBytes((ushort)1);
            var actualPropsTrunkId = BitConverter.GetBytes((ushort)1);

            var buffer = new byte[Edge.Size];
            Array.Copy(actualEdgeType, buffer, 4);
            Array.Copy(actualPropsId, 0, buffer, 4, 4);
            Array.Copy(actualEndVertexId, 0, buffer, 8, 4);
            Array.Copy(actualEndTrunkId, 0, buffer, 12, 2);
            Array.Copy(actualPropsTrunkId, 0, buffer, 14, 2);

            var subject = Edge.Read(buffer, 0);
            subject.EdgeType.Should().Be(6);
            subject.EndVertexId.Should().Be(3);
            subject.EndTrunkId.Should().Be(1);
            subject.PropsCellId.Should().Be(10);
            subject.PropsTrunkId.Should().Be(1);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void EdgeWritesThenReadsAsExpected()
        {
            var cellAddress = new CellAddress(1, 3);
            var propsAddress = new CellAddress(1, 5);
            var expected = new Edge(6, cellAddress, propsAddress, EdgeDirections.Bidirectional);

            var buffer = new byte[Edge.Size];
            expected.Write(buffer, 0);

            var actual = Edge.Read(buffer, 0);
            actual.EdgeType.Should().Be(expected.EdgeType);
            actual.EndVertexId.Should().Be(expected.EndVertexId);
            actual.EndTrunkId.Should().Be(expected.EndTrunkId);
            actual.PropsCellId.Should().Be(expected.PropsCellId);
            actual.PropsTrunkId.Should().Be(expected.PropsTrunkId);
        }

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeEqualityIsKeyValueEquality()
        ////{
        ////    var subject1 = new Edge(99, 12200, 01);
        ////    var subject2 = new Edge(99, 12200, 01);
        ////    (subject1 == subject2).Should().BeTrue();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeInequalityIsKeyInequality()
        ////{
        ////    var subject1 = new Edge(99, 12200, 01);
        ////    var subject2 = new Edge(98, 12200, 01);
        ////    (subject1 != subject2).Should().BeTrue();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeInequalityIsValueInequality()
        ////{
        ////    var subject1 = new Edge(98, 124500, 01);
        ////    var subject2 = new Edge(98, 12200, 01);
        ////    (subject1 != subject2).Should().BeTrue();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeEqualsIsValueEquality()
        ////{
        ////    var subject1 = new Edge(99, 12200, 01);
        ////    var subject2 = new Edge(99, 12200, 01);
        ////    subject1.Equals(subject2).Should().BeTrue();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeEqualsIsKeyInequality()
        ////{
        ////    var subject1 = new Edge(99, 12200, 01);
        ////    var subject2 = new Edge(98, 12200, 01);
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeEqualsIsValueInequality()
        ////{
        ////    var subject1 = new Edge(98, 124500, 01);
        ////    var subject2 = new Edge(98, 12200, 01);
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeIsNotEqualToNull()
        ////{
        ////    object other = null;
        ////    new Edge(98, 124500, 01).Equals(other).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeGetHashCodeIsConsistent()
        ////{
        ////    var subject = new Edge(98, 124500, 01);
        ////    subject.GetHashCode().Should().Be(subject.GetHashCode());   
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeGetHashCodeIsDifferentForDifferentKey()
        ////{
        ////    var subject1 = new Edge(98, 124500, 01);
        ////    var subject2 = new Edge(101, 124500, 01);
        ////    subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeGetHashCodeIsDifferentForDifferentValue()
        ////{
        ////    var subject1 = new Edge(101, 124500, 01);
        ////    var subject2 = new Edge(101, 1200, 01);
        ////    subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeGetHashCodeIsDifferentForDifferentKeyAndValue()
        ////{
        ////    var subject1 = new Edge(88, 124500, 01);
        ////    var subject2 = new Edge(101, 1200, 01);
        ////    subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeObjectEqualsIsEquality()
        ////{
        ////    var subject1 = new Edge(98, 124500, 01);
        ////    object subject2 = new Edge(98, 124500, 01);
        ////    subject1.Equals(subject2).Should().BeTrue();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeObjectEqualsIsInequalityForDifferentKey()
        ////{
        ////    var subject1 = new Edge(99, 124500, 01);
        ////    object subject2 = new Edge(98, 124500, 01);
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeObjectEqualsIsInequalityForDifferentValue()
        ////{
        ////    var subject1 = new Edge(99, 124500, 01);
        ////    object subject2 = new Edge(99, 500, 01);
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeObjectEqualsIsInequalityForDifferentKeyAndValue()
        ////{
        ////    var subject1 = new Edge(8769, 124500, 01);
        ////    object subject2 = new Edge(99, 500, 01);
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}

        ////[TestMethod, TestCategory("Unit Test")]
        ////public void EdgeObjectEqualsIsInequalityForDifferentType()
        ////{
        ////    var subject1 = new Edge(99, 124500, 01);
        ////    object subject2 = new object();
        ////    subject1.Equals(subject2).Should().BeFalse();
        ////}
    }
}
